/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.dataset.snort;

import nfse.NetFSERecord;
import nfse.NetFSEUtil;

import java.io.RandomAccessFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

public class SnortSyslogRecord extends SnortRecord {

    public SnortSyslogRecord() {

    }

    public static void main(String[] args) {
        SnortSyslogRecord rec = new SnortSyslogRecord();
        rec.parse(args, rec);
    }   
    
    
    /***************************************************************************
     * This method will return a single-line event from a gzipped data stream.
     * Bytes are read until the '\n' character is read. This method is
     * appropriate for any event type whose records are written on single lines.
     * Multi-line records need to override this function.
     * 
     * @param dataIn
     *            The gzipped data stream (ultimately a file) from which events
     *            are being read and parsed.
     * @return The unparsed event as a String.
     */
    public String getRecordLine(GZIPInputStream dataIn) {
        try {
            StringBuffer line = new StringBuffer();
            int ch = 0;
            do {
                ch = dataIn.read();
                line.append((char) ch);

            } while ((ch != -1) && ((char) ch != '\n'));
            return line.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***************************************************************************
     * This method will return a single-line event from a RandomAccessFile using
     * the readLine() method. This method is appropriate for any event type
     * whose records are written on single lines. Multi-line records need to
     * override this function.
     * 
     * @param dataIn
     *            The file from which events are being read and parsed.
     * @return The unparsed event as a String.
     */
    public String getRecordLine(RandomAccessFile dataIn) {
        try {
            String line = dataIn.readLine();
            return line;
        } catch (Exception e) {

        }
        return null;
    }

    public SnortSyslogRecord(int sensor) {
        this.setSensorID(sensor);
    }

    public NetFSERecord generate(String line, int sensor) throws Exception {
        SnortSyslogRecord rec = new SnortSyslogRecord(sensor);
        // System.out.println(line);
        rec.setInitialString(line);
        line = line.trim();

        int idx1 = line.indexOf(";");
        int idx2 = line.indexOf(";", idx1 + 2);
        int colIdx = line.indexOf(":", idx2 + 15);

        String tsStr = line.substring(0, idx1);
        if (!tsStr.equals("-1")) {
            java.sql.Timestamp ts = new java.sql.Timestamp(Long.parseLong(tsStr) * 1000);
            rec.setStartTS(ts);
        } else {
            tsStr = line.substring(idx2, colIdx);
            java.sql.Timestamp ts = NetFSEUtil.timestampFromSyslog(tsStr);
            rec.setStartTS(ts);
            line = ts.getTime() / 1000 + line.substring(idx1);
            idx1 = line.indexOf(";");
            idx2 = line.indexOf(";", idx1 + 2);
            colIdx = line.indexOf(":", idx2 + 15);
        }

        line = line.substring(colIdx + 1).trim();
        //System.out.println("====================================");
        //System.out.println("LINE: '" + line + "'");
        Pattern p = Pattern
                .compile("\\[([0-9:]+)\\] (.*) \\[Classification: (.*)\\] \\[Priority: (.*)\\] \\{(.*)\\} (.*)");
        Matcher m = p.matcher(line);
        boolean b = m.matches();
        if (b) {
            int count = m.groupCount();
            //System.out.println("--START--");
            //for (int i = 1; i <= count; i++)
            //    System.out.print(i + ": '" + m.group(i) + "', ");
            //System.out.println("\n--END--");

            String value = m.group(1);
            String[] values = value.split(":");
            rec.sid = Integer.parseInt(values[2]);
            rec.cid = Integer.parseInt(values[1]);
            rec.sigClassID = Integer.parseInt(values[0]);

            rec.sigName = m.group(2);
            rec.classification = m.group(3);
            rec.priority = Integer.parseInt(m.group(4).trim());

            value = m.group(5);
            if (value.startsWith("{")) {
                rec.proto = NetFSEUtil.getProtocol(value.substring(1, value.length() - 1));
            } else {
                rec.proto = NetFSEUtil.getProtocol(value);
            }

            values = m.group(6).split(" ");
            String srcIP = "";
            int srcPort = -1;
            String[] srcValues = values[0].split(":");
            if (srcValues.length <= 1) {
                srcIP = values[0];
            } else {
                srcIP = srcValues[0];
                srcPort = Integer.parseInt(srcValues[1]);
            }
            rec.setSrcAddr(srcIP);
            rec.srcPort = srcPort;

            String dstIP = "";
            int dstPort = -1;
            String[] dstValues = values[2].split(":");
            if (dstValues.length <= 1) {
                dstIP = values[2];
            } else {
                dstIP = dstValues[0];
                dstPort = Integer.parseInt(dstValues[1]);
            }
            rec.dstPort = dstPort;

            rec.setSrcIP(NetFSEUtil.convertIPtoLong(srcIP));
            rec.setDstIP(NetFSEUtil.convertIPtoLong(dstIP));

        } else {
            rec.setTimestamp(null);
        }

        //System.out.println(rec.toMultiLine());

        if (rec.getTimestamp() == null)
            return null;

        return rec;
    }

    public boolean isSyslog() {
        return true;
    }

}